package com.skyjing.askit

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.ActivityManager
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.Surface
import android.view.WindowManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.util.ArrayList


@SuppressLint("StaticFieldLeak")
object AsTool {
    private var context: Context? = null

    @JvmStatic
    fun init(context: Context) {
        AsTool.context = context
    }

    @JvmStatic
    fun getContent(): Context? {
        return context
    }

    @JvmStatic
    fun getApp(): Context? {
        return context
    }

    /**
     * 将px值转换为dip或dp值，保证尺寸大小不变
     * @param pxValue
     * @return
     */
    @JvmStatic
    fun px2dp(pxValue: Float): Int {
        val scale: Float? = context?.resources?.displayMetrics?.density
        return (pxValue / scale!! + 0.5f).toInt()
    }

    /**
     * dp转px
     * @param dpVal
     * @return
     */
    @JvmStatic
    fun dp2px(dpVal: Float): Int {
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dpVal, context?.resources?.displayMetrics
        ).toInt()
    }

    /**
     * 将px值转换为sp值，保证文字大小不变
     * @param pxValue
     * @return
     */
    @JvmStatic
    fun px2sp(pxValue: Float): Int {
        val fontScale: Float? = context?.resources?.displayMetrics?.scaledDensity
        return (pxValue / fontScale!! + 0.5f).toInt()
    }

    /**
     * 将sp值转换为px值，保证文字大小不变
     * @param spValue
     * @return
     */
    @JvmStatic
    fun sp2px(spValue: Float): Int { //        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
//        return (int) (spValue * fontScale + 0.5f);
        return TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP,
            spValue, context?.resources?.displayMetrics
        ).toInt()
    }

    /**
     * 获取版本号
     * @return
     */
    @JvmStatic
    fun getVersionName(): String? {
        try {
            return context?.packageManager?.getPackageInfo(
                context?.packageName, 0
            )?.versionName
        } catch (e: PackageManager.NameNotFoundException) {
        }
        return null
    }

    /**
     * 获取版本号
     * @return
     */
    @JvmStatic
    fun getVersionCode(): Int {
        try {
            val pm = context?.packageManager
            val pi = pm?.getPackageInfo(context?.packageName, 0)
            return pi?.versionCode ?: -1
        } catch (e: PackageManager.NameNotFoundException) {
        }
        return 0
    }

    /**
     * 获取屏幕宽度，px
     * @return
     */
    @JvmStatic
    fun getScreenWidth(): Float {
        val dm: DisplayMetrics = context?.resources?.displayMetrics!!
        return dm.widthPixels.toFloat()
    }

    /**
     * 获取屏幕高度，px
     * @return
     */
    @JvmStatic
    fun getScreenHeight(): Float? {
        val dm: DisplayMetrics? = context?.resources?.displayMetrics
        return dm?.heightPixels?.toFloat()
    }

    /**
     * 获取屏幕像素密度
     * @return
     */
    @JvmStatic
    fun getDensity(): Float? {
        val dm: DisplayMetrics? = context?.resources?.displayMetrics
        return dm?.density
    }

    /**
     * 获取scaledDensity
     * @return
     */
    @JvmStatic
    fun getScaledDensity(): Float? {
        val dm: DisplayMetrics? = context?.resources?.displayMetrics
        return dm?.scaledDensity
    }

    /**
     * 获取颜色
     */
    @JvmStatic
    fun getColor(id: Int): Int? {
        return context?.let { ContextCompat.getColor(it, id) }
    }

    @JvmStatic
    fun getPageName(): String? {
        return context?.packageName
    }

    /**
     * 将byte数组转换成指定字符集
     */
    @JvmStatic
    fun String(data: ByteArray, charset: String): String =
        java.lang.String(data, charset) as String

    /**
     * 判断当前APP是否存活
     */
    @JvmStatic
    fun isAppAlive(context: Context, packageName: String): Boolean {
        val activityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val processInfos = activityManager.runningAppProcesses
        for (i in processInfos.indices) {
            if (processInfos[i].processName == packageName) {
                return true
            }
        }
        return false
    }

//    private fun getAppSignatureHash(packageName: String, algorithm: String): String? {
//        if (isSpace(packageName)) return ""
//        val signature: Array<Signature> = getAppSignature(packageName)
//        return if (signature == null || signature.size <= 0) "" else bytes2HexString(
//            hashTemplate(
//                signature[0].toByteArray(), algorithm
//            )
//        )
//            .replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0")
//    }

    private fun isSpace(s: String?): Boolean {
        if (s == null) return true
        var i = 0
        val len = s.length
        while (i < len) {
            if (!Character.isWhitespace(s[i])) {
                return false
            }
            ++i
        }
        return true
    }

    fun getAppSignature(): Array<Signature?>? {
       return if (context != null){
           getAppSignature(this.context?.packageName)
        }else{
            null
        }
    }

    /**
     * Return the application's signature.
     *
     * @param packageName The name of the package.
     * @return the application's signature
     */
    @JvmStatic
    fun getAppSignature(packageName: String?): Array<Signature?>? {
        return if (isSpace(packageName)) null else try {
            val pm: PackageManager? = getApp()?.packageManager
            @SuppressLint("PackageManagerGetSignatures") val pi =
                pm?.getPackageInfo(packageName, PackageManager.GET_SIGNATURES)
            pi?.signatures
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
            null
        }
    }

    /**
     * 设置安全窗口，禁用系统截屏。防止 App 中的一些界面被截屏，并显示在其他设备中造成信息泄漏。
     * （常见手机设备系统截屏操作方式为：同时按下电源键和音量键。）
     *
     * @param activity
     */
    @JvmStatic
    fun noScreenshots(activity: Activity) {
        activity.window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
    }

    /**
     * 判断是否锁屏
     *
     * @param context 上下文
     * @return `true`: 是<br></br>`false`: 否
     */
    @JvmStatic
    fun isScreenLock(context: Context): Boolean {
        val km = context
            .getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
        return km.isKeyguardLocked
    }

    /**
     * 获取屏幕旋转角度
     *
     * @param activity activity
     * @return 屏幕旋转角度
     */
    @JvmStatic
    fun getScreenRotation(activity: Activity): Int {
        return when (activity.windowManager.defaultDisplay.rotation) {
            Surface.ROTATION_0 -> 0
            Surface.ROTATION_90 -> 90
            Surface.ROTATION_180 -> 180
            Surface.ROTATION_270 -> 270
            else -> 0
        }
    }

    /**
     * 判断是否竖屏
     *
     * @param context 上下文
     * @return `true`: 是<br></br>`false`: 否
     */
    @JvmStatic
    fun isPortrait(context: Context): Boolean {
        return context.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
    }

    /**
     * 判断是否横屏
     *
     * @param context 上下文
     * @return `true`: 是<br></br>`false`: 否
     */
    @JvmStatic
    fun isLandscape(context: Context): Boolean {
        return context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
    }

    /**
     * 设置屏幕为横屏
     *
     * 还有一种就是在Activity中加属性android:screenOrientation="landscape"
     *
     * 不设置Activity的android:configChanges时，切屏会重新调用各个生命周期，切横屏时会执行一次，切竖屏时会执行两次
     *
     * 设置Activity的android:configChanges="orientation"时，切屏还是会重新调用各个生命周期，切横、竖屏时只会执行一次
     *
     * 设置Activity的android:configChanges="orientation|keyboardHidden|screenSize"（4.0以上必须带最后一个参数）时
     * 切屏不会重新调用各个生命周期，只会执行onConfigurationChanged方法
     *
     * @param activity activity
     */
    @SuppressLint("SourceLockedOrientationActivity")
    @JvmStatic
    fun setLandscape(activity: Activity) {
        activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
    }

    /**
     * 设置屏幕为竖屏
     *
     * @param activity activity
     */
    @SuppressLint("SourceLockedOrientationActivity")
    @JvmStatic
    fun setPortrait(activity: Activity) {
        activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
    }

    /**
     * 跳至填充好phoneNumber的拨号界面
     *
     * @param context     上下文
     * @param phoneNumber 电话号码
     */
    @JvmStatic
    fun dial(context: Context, phoneNumber: String) {
        context.startActivity(Intent(Intent.ACTION_DIAL, Uri.parse("tel:$phoneNumber")))
    }

    /**
     * 拨打电话
     * 需添加权限 `<uses-permission android:name="android.permission.CALL_PHONE"/>`
     *
     * @param context     上下文
     * @param phoneNumber 电话号码
     */
    @JvmStatic
    fun callPhone(context: Context, phoneNumber: String) {
        if (phoneNumber.isNotEmpty()) {
            val phoneNumber1 = phoneNumber.trim { it <= ' ' } // 删除字符串首部和尾部的空格
            // 调用系统的拨号服务实现电话拨打功能
            // 封装一个拨打电话的intent，并且将电话号码包装成一个Uri对象传入
            val intent = Intent(Intent.ACTION_CALL, Uri.parse("tel:$phoneNumber1"))
            if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                return
            }
            context.startActivity(intent) // 内部类
        }
    }

    /**
     * 检查权限
     * @param context
     * @param permission 例如 Manifest.permission.READ_PHONE_STATE
     * @return
     */
    @JvmStatic
    fun checkPermission(context: Context, permission: String): Boolean {
        var result = false
        if (Build.VERSION.SDK_INT >= 23) {
            result = try {
                val clazz = Class.forName("android.content.Context")
                val method = clazz.getMethod("checkSelfPermission", String::class.java)
                val rest = method.invoke(context, permission) as Int
                rest == PackageManager.PERMISSION_GRANTED
            } catch (e: Exception) {
                false
            }
        } else {
            val pm = context.packageManager
            if (pm.checkPermission(permission, context.packageName) == PackageManager.PERMISSION_GRANTED) {
                result = true
            }
        }
        return result
    }

    @JvmStatic
    fun initPackageManager(mContext: Context): List<PackageInfo> {
        val mPackageManager = mContext.packageManager
        return mPackageManager.getInstalledPackages(0)
    }

    /**
     * 包名是否存在
     * @param mContext 实体
     * @param packageName 待检测 包名
     * @return 结果
     */
    @JvmStatic
    fun haveExistPackageName(mContext: Context, packageName: String): Boolean {
        val packageInfos = initPackageManager(mContext)
        val mPackageNames: MutableList<String> = ArrayList()
        for (i in packageInfos.indices) {
            mPackageNames.add(packageInfos[i].packageName)
        }
        return mPackageNames.contains(packageName)
    }
}